/*
 * @Project Name: demo
 * @File Name: AuthorizingRealm
 * @Package Name: com.sayimo.cn.test.demo.shiro
 * @Date: 2018/4/22 21:45
 * @Creator: linshixing-1199
 * @line------------------------------
 * @修改人:
 * @修改时间:
 * @修改内容:
 */

package com.sm.shoplook.shiro;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.sm.shoplook.constant.Constant;
import com.sm.shoplook.dao.mapper.system.RoleMenuMapper;
import com.sm.shoplook.domain.system.Permission;
import com.sm.shoplook.domain.system.User;
import com.sm.shoplook.service.system.PermissionService;
import com.sm.shoplook.service.system.UserService;
import com.sm.shoplook.vo.base.ApiResult;
import com.sm.shoplook.vo.system.user.resp.UserRoleRespVo;

/**
 * @author chenpy-1072
 * @desc AuthorizingRealm
 * @date 2018/4/22 21:45
 * @see
 */
public class MySqlAuthorizingRealm extends AuthorizingRealm {

	private static final Logger LOGGER = LoggerFactory.getLogger(MySqlAuthorizingRealm.class);
	@Autowired
	private UserService userService;
	@Autowired
	private PermissionService permissionService;
	@Autowired
	private RoleMenuMapper roleMenuMapper;

	/**
	 * 获取用户角色和权限信息
	 * @param principals
	 * @return
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		Principal principal = (Principal) principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
		ApiResult<UserRoleRespVo> userRoleRespVoApiResult = userService.selectUserRoleByUserId(principal.getUserId());
		UserRoleRespVo role = userRoleRespVoApiResult.getData();
		if (role == null) {
			return simpleAuthorizationInfo;
		}
		String roleCode = role.getRoleCode();
		Set<String> roleCodes = new HashSet<>();
		roleCodes.add(role.getRoleCode());
		simpleAuthorizationInfo.setRoles(roleCodes);
		ApiResult<List<Permission>> listApiResult = permissionService.selectPermissionsByRoleCode(roleCode);
		List<Permission> permissions = listApiResult.getData();
		if (CollectionUtils.isEmpty(permissions)) {
			return simpleAuthorizationInfo;
		}
		Session session = SecurityUtils.getSubject().getSession();
		Set<String> permissionCodes = permissions.stream().map(permission -> permission.getPermissionCode())
				.collect(Collectors.toSet());
		List<String> menuCodes = roleMenuMapper.selectRoleMenuCodes(roleCode);
        if (CollectionUtils.isNotEmpty(menuCodes)) {
            permissionCodes.addAll(menuCodes);
        }
        session.setAttribute("permissionCodes", permissionCodes.toArray());
        simpleAuthorizationInfo.setStringPermissions(permissionCodes);
		return simpleAuthorizationInfo;
	}

	/**
	 * 用户验证（登录）
	 * @param token
	 * @return
	 * @throws AuthenticationException
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		LOGGER.info("身份认证方法：MyShiroRealm.doGetAuthenticationInfo()");
		UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
		// 从数据库获取对应用户名密码的用户
		ApiResult<List<User>> listApiResult = userService.selectUserByUserName(usernamePasswordToken.getUsername());
		List<User> userList = listApiResult.getData();
		LOGGER.info("userList: {}", userList.get(0));
		User user;
		if (CollectionUtils.isEmpty(userList)) {
			throw new AccountException("用户不存在！");
		} else {
			user = userList.get(0);
			String pwd = (new SimpleHash("MD5", usernamePasswordToken.getPassword(),
					ByteSource.Util.bytes(new String(Hex.encode(Constant.HASH_KEY.getBytes()))), 999)).toString();
			// 账号已被锁定
			if (user.getStatus() == 2) {
				/**
				 * 如果用户的status为禁用。那么就抛出<code>DisabledAccountException</code>
				 */
				throw new DisabledAccountException("帐号已经禁止登录！");
			} else if (!user.getPassword().equals(pwd)) {
				throw new IncorrectCredentialsException("密码错误");
			}
		}
		return new SimpleAuthenticationInfo(new Principal(user), user.getPassword(),
				ByteSource.Util.bytes(new String(Hex.encode(Constant.HASH_KEY.getBytes()))), getName());
	}

	@Override
	protected void clearCachedAuthenticationInfo(PrincipalCollection principals) {
		super.clearCachedAuthenticationInfo(principals);
	}

	@Override
	protected void clearCachedAuthorizationInfo(PrincipalCollection principals) {
		super.clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 加密 SHA-1 MD5
	 * @param args
	 */
	public static void main(String[] args) {
		// SimpleHash参数说明@param 1:加密方式 @param 2:加密串 @param 3: 盐 @param 4:迭代次数
		String pwd = (new SimpleHash("MD5", "admin",
				ByteSource.Util.bytes(new String(Hex.encode(Constant.HASH_KEY.getBytes()))), 999)).toString();
		System.out.println(pwd);
	}
}
